/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/* 
 * Copyright (c) 2009 City University of Hong Kong
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License m_version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author: Wilson Thong (wilsonwk@ee.cityu.edu.hk) 
 */
#ifndef BMSN_ROUTING_H
#define BMSN_ROUTING_H

#include "ns3/ipv4-routing-table-entry.h"
#include "ns3/ipv4-list-routing.h"
#include "ns3/ipv4-routing-protocol.h"
#include "ns3/random-variable.h"
#include "jitter-sim-include.h"
#include "bmsn-topology.h"
#include "bmsn-path-selector-tag.h"

/// The default priority of the BmsnRouting protocol
#define DEFAULT_BMSN_ROUTING_PRI (10)

namespace ns3 {
namespace eecityu {

using namespace ns3;

/**
 * \brief Routing table and packet forwarding implementation for BMSN topology
 * 
 * For simulation running over BMSN topology, a specific class
 * is used to take the advantages offered by the regularity of BMSN 
 * topology. 
 *
 * BmsnRouting is such a class that implement the routing table lookup
 * and packet forwarding. As the structure of a BMSN topology is known,
 * no shortest path calculation is needed before coming up a next hop
 * when given a destination address.
 *
 * It contains a static object of BmsnRouting, and this object implements
 * the BMSN routing for the entire simulation.
 *
 * \see BmsnGenerator
 * \see BmsnPathSelectorTag
 */
class BmsnRouting : public Ipv4RoutingProtocol
{
public:
  static TypeId GetTypeId (void);

  BmsnRouting(void);

  /**
   * \brief Query routing cache for an existing route, for an outbound packet
   *
   * \see Ipv4RoutingProtocol
   */
  virtual Ptr<Ipv4Route> RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr);
  
  /**
   * \brief Route an input packet (to be forwarded or locally delivered)
   *
   * \see Ipv4RoutingProtocol::RouteInput
   */ 
  virtual bool RouteInput  (Ptr<const Packet> p, const Ipv4Header &header, Ptr<const NetDevice> idev, 
                             UnicastForwardCallback ucb, MulticastForwardCallback mcb, 
                             LocalDeliverCallback lcb, ErrorCallback ecb);
  /**
   * \see Ipv4RoutingProtocol::NotifyInterfaceUp
   */
  virtual void NotifyInterfaceUp (uint32_t interface);
  /**
   * \see Ipv4RoutingProtocol::NotifyInterfaceDown
   */
  virtual void NotifyInterfaceDown (uint32_t interface);

  /**
   * \see Ipv4RoutingProtocol::NotifyAddAddress
   */
  virtual void NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address);

  /**
   * \see Ipv4RoutingProtocol::NotifyRemoveAddress
   */
  virtual void NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address);

  /**
   * \see Ipv4RoutingProtocol::SetIpv4
   */
  virtual void SetIpv4 (Ptr<Ipv4> ipv4);

  /**
   * \brief set the node into which this BmsnRouting 
   * protocol object is aggregating
   *
   * It reads the IP address of the node and extracts its location information.
   * The location information is embedded into the IP address according to
   * the rule set by the BmsnTopology::IsBmsnTopology ().
   *
   * \param n The node that this BmsnRouting protocol object is installing to
   */
  void SetNode (Ptr<Node> n);
  /**
   * \brief Return the priority of the BmsnRouting protocol
   *
   * \return The priority of the BmsnRouting protocol
   */
  int16_t GetPriority () const;

private:
  /**
   * \brief Lookup an exiting route from the current location to the
   * destination specified in a packet.
   *
   * \param dest The destination a packet is going to from the current
   * location
   * \param p The packet current being routed.
   * \param idev The net device from which the packet came
   * \return An exiting route for the packet at the current location
   *
   * Any one of the four routes can be returned, 
   * - A route for the north neighbor,
   * - a route for the east neighbor,
   * - a route for the south neighbor, or
   * - a route for the west neighbor.
   *
   * A correct route is chosen according to the horizontal and
   * vertical distances between the destination node and the current
   * node, where the distance is measured in number of hops. 
   *
   * When multiple routes are found, one of the route is chosen
   * according to the BmsnPathSelectorTag added into the packet p,
   * if such a tag is found.
   *
   * \see BmsnPathSelectorTag
   */
  Ptr<Ipv4Route> LookupBmsnRoute (Ipv4Address dest, Ptr<Packet> p, Ptr<const NetDevice> idev);
  /**
   * \brief Get the x-location of the node that this BmsnRouting protocol object
   * is aggregiated to
   *
   * \return The x-coordinate of a BMSN node
   */
  uint32_t GetXLocation () const;
  /**
   * \brief Get the y-location of the node that this BmsnRouting protocol object
   * is aggregiated to
   *
   * \return The y-coordinate of a BMSN node
   */
  uint32_t GetYLocation () const;
  /**
   * \brief Get the number of rows of the BMSN topology
   *
   * \return The number of rows of the BMSN topology
   */
  uint32_t GetNRows () const;
  /**
   * \brief Initialize the four routes that forwards packets to each of the
   * four neighbors
   *
   * \param n The node to which the BmsnRouting protocol object is aggregated
   */
  void InitializeRoutes (Ptr<Node> n);
  /**
   * \brief Choose an exit interface randomly for the packet
   *
   * \param p The packet with a BmsnPathSelectorTag added as a packet tag
   * \param goNorth true if North is an feasible exit interface
   * \param goEast  true if East  is an feasible exit interface
   * \param goSouth true if South is an feasible exit interface
   * \param goWest  true if West  is an feasible exit interface
   * \return One of the four direction, North, East, South, or West, for
   * the packet to exit the local node, or None if no exit direction is chosen.
   *
   * An exit is returned randomly among the feasible exits
   */
  BmsnPathSelectorTag::ExitDirection ChooseExitByRandom (
    Ptr<Packet> p,
    bool goNorth,
    bool goEast,
    bool goSouth,
    bool goWest
    ) const;
  /**
   * \brief Choose an exit interface according to the default priority among
   * the four exits
   *
   * The default priority is
   * - 1) North,
   * - 2) East,
   * - 3) South, and finally
   * - 4) West.
   *
   * Among the feasible exits, the one with the highest priority is chosen
   * as the exit interface for the packet currently being routed.
   *
   * \param p The packet currently being routed
   * \param goNorth True if North is an feasible exit
   * \param goEast  True if East  is an feasible exit
   * \param goSouth True if South is an feasible exit
   * \param goWest  True if West  is an feasible exit
   * \return The exit interface for the packet
   */
  BmsnPathSelectorTag::ExitDirection ChooseExitByDefault (
    Ptr<Packet> p,
    bool goNorth,
    bool goEast,
    bool goSouth,
    bool goWest
    ) const;
  /**
   * \brief Choose a route based upon the indicated exit direction.
   *
   * \param e The current preferred exit route for the packet
   * \param goNorth true if North is an feasible exit interface
   * \param goEast  true if East  is an feasible exit interface
   * \param goSouth true if South is an feasible exit interface
   * \param goWest  true if West  is an feasible exit interface
   * \return A route corresponding to the exit direction specified by the
   * input argument. If the input argument is None, the default behavior
   * selects North first, then East, then South, and finally West, depending
   * if these directions are feasible exits.
   */
  Ptr<Ipv4Route> ChooseRouteByExit (
    BmsnPathSelectorTag::ExitDirection e,
    bool goNorth,
    bool goEast,
    bool goSouth,
    bool goWest
    ) const;
  /**
   * \brief Defien the deflection bahavior. 
   *
   * Once deflected, the packet being routed may exit the local node
   * from the non-preferred interfaces.
   *
   * \param idev The net device from which the packet comes in
   * \param exit The most preferred exit interface for the packet
   * \param goNorth True if North is an feasible exit
   * \param goEast True if East is an feasible exit
   * \param goSouth True if South is an feasible exit
   * \param goWest True if West is an feasible exit
   * \param p The packet now being routed/delfected
   * \return A route for the packet being routed, or 0 if
   * no deflection is made.
   */
  Ptr<Ipv4Route> ChooseRouteByDeflection (
    Ptr<const NetDevice> idev,
    Ptr<Ipv4Route> exit,
    bool goNorth,
    bool goEast,
    bool goSouth,
    bool goWest,
    Ptr<Packet> p
    );
  /**
   * \brief Deflect the packet away from the exit interface
   *
   * This method defines the actual deflection machemism. It deflects packets
   * away from the exit interface. The candidate interfaces who are allowed to
   * receive the deflected packet must not be the input interface, nor the 
   * interface's queue is full. Final deflected exit interface is selected randomly
   * from within the candidates, where the randomness are determined by the 
   * BmsnPathSelectorTag tagged to the packet
   *
   * \param idev The input net device for the packet
   * \param exit The original and preferred route for the packet to exit
   * \param goNorth True if North is a feasible exit direction
   * \param goEast True if East is a feasible exit direction
   * \param goSouth True if South is a feasible exit direction
   * \param goWest True if West is a feasible exit direction
   * \param p The packet now being routed/delfected
   * \return The final exit route for the packet after being deflected
   *
   */
  Ptr<Ipv4Route> DoDeflect (
    Ptr<const NetDevice> idev,
    Ptr<Ipv4Route> exit,
    bool goNorth,
    bool goEast,
    bool goSouth,
    bool goWest,
    Ptr<Packet> p
    );
  /**
   * \brief Get a route by exit direction
   * 
   * \param e An exit direction
   * \return The appropriate route for the given exit direction
   */
  Ptr<Ipv4Route> GetRouteTo (BmsnPathSelectorTag::ExitDirection e) const;
  /**
   *
   */
  void DoDispose (void);

  /// Set to true if deflection is to be enabled during routing
  bool m_enableDeflection;
  /// Set to true to introduce randomness when routing a packet among muliple paths
  bool m_enableRandRouting;
  /// The priority among all routing protocol
  int16_t m_priority;
  /** 
   * The x-coordinate of the node that this BmsnRouting 
   * protocol object is attached 
   */
  uint32_t m_xLocation;
  /** 
   * The y-coordinate of the node that this BmsnRouting 
   * protocol object is attached 
   */
  uint32_t m_yLocation;
  /**
   * Store the number of rows of the BMSN topology
   */
  uint32_t m_nRows;
  /// The route to the north neighbor
  Ptr<Ipv4Route> m_northRoute;
  /// The routeto the east neighbor
  Ptr<Ipv4Route> m_eastRoute;
  /// The route to the south neighbor
  Ptr<Ipv4Route> m_southRoute;
  /// The route to the west neighbor
  Ptr<Ipv4Route> m_westRoute;
  /// The route to the localhost
  Ptr<Ipv4Route> m_localRoute;
  /**
   * Refer to the ipv4 protocol object of the node on which 
   * this BmsnRouting is installed
   */
  Ptr<Ipv4> m_ipv4;
  UniformVariable m_rand;
};

} // namespace eecityu
} // namespace ns3

#endif // #ifndef BMSN_ROUTING_H
